package mobileMoney;

import sim.engine.SimState;
import sim.field.continuous.Continuous2D;
import sim.field.network.Edge;
import sim.util.Bag;
import sim.util.Double2D;
import sim.util.MutableDouble2D;

public class Fraudster extends Client {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void step(SimState state) {
		Clients clients = (Clients) state;
		double amount;
		if (this.active) {
			// activates or deactivate a client and upgrade status
			evaluateStatus(clients.random.nextDouble());


			Continuous2D land = clients.land;
			Double2D me = clients.land.getObjectLocation(this);
			MutableDouble2D newLoc = new MutableDouble2D();
			// Go through my buddies and determine how much I want to be near
			// them
			MutableDouble2D forceVector = new MutableDouble2D();
			Bag out = clients.contacts.getEdgesOut(this);

			int len = out.size();
			// loop the contacts
			int contact = 0;
			Client clientE = new Client();

			if (len > 0) {
				contact = clients.random.nextInt(len);
			} else {
				contact = 0;
			}
			Edge e = (Edge) (out.get(contact));
			Client clientB = (Client) (e.getOtherNode(this));

			if (this.balance < this.profile.maxBalance) {
				amount = this.profile.maxBalance - this.balance;
				if (this.deposit(amount)) {
					clients.getTrans().add(
							new Transaction(clients.schedule.getSteps(), this,
									(short) 1, amount, " Money Laundering", 1));
				}
			}

			// probability to make a transaction

			

			if (clients.transactionRate < clients.random.nextDouble()) {

				amount = 0;
				// select one transaction
				int numOp = clients.random.nextInt(100);
				TransactionType operation = clients.getTypes().get(numOp);
				while (operation.maxVal > this.balance && !operation.nature) {
					operation = clients.getTypes().get(
							clients.random.nextInt(100));
				}

				this.numTransactions++;

				if (operation.nature) {
					// true = deposit

					amount = clients.random.nextLong((long) operation.maxVal)
							+ clients.random.nextDouble();

					if (this.deposit(amount)) {
						clients.getTrans().add(
								new Transaction(clients.schedule.getSteps(),
										this,  (short) 1, amount, "",1));
					}
				} else { // false = withdraw

					amount = clients.random.nextLong((long) operation.maxVal)
							+ clients.random.nextDouble();

				}
				// probability for a transfer when is withdraw
				if (clients.random.nextBoolean(0.9) && len > 0) {

					this.numTransfers++;
					// only when is possible to deposit
					if (clientB.profile.getTransactionLimit()< amount) {
						amount = clientB.profile.getTransactionLimit();
					}
					if (clientB.checkDeposit(amount)) {
						if (this.withdraw(amount)) {
							clients.getTrans()
									.add(new Transaction(clients.schedule
											.getSteps(), this, clientB,
											(short) 3,
											-amount, ""));
							clientB.deposit(amount);
							clients.getTrans().add(
									new Transaction(
											clients.schedule.getSteps(),
											clientB, this, (short) 3, amount,
											" deposited from B ", 1));
						}
					}

				} else {
					if (this.withdraw(amount)) {
						clients.getTrans().add(
								new Transaction(clients.schedule.getSteps(),
										this,  (short) 2, -amount, "", 1));
					}
				}
			}

			// move the agents
			double lx = clients.randomMultiplier
					* (clients.random.nextDouble() * 6 - 3);
			if (lx > 100)
				lx = 99;
			double ly = clients.randomMultiplier
					* (clients.random.nextDouble() * 6 - 3);
			if (ly > 100)
				ly = 99;

			newLoc.addIn(new Double2D(lx, ly));
			newLoc.addIn(me);
			clients.land.setObjectLocation(this, new Double2D(newLoc));

		}

	}

	public String toString() {
		return "F" + Integer.toString(this.hashCode());
	}

}
